﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Collections;
using Newtonsoft.Json.Converters;
using System.Linq;
using AutoMapper;
using Newtonsoft.Json.Serialization;

namespace System {
    public static partial class Extention {
        /// <summary>
        /// 构造函数
        /// </summary>
        static Extention() {
            JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() => {
                JsonSerializerSettings setting = new JsonSerializerSettings();
                setting.DateFormatHandling = DateFormatHandling.MicrosoftDateFormat;
                setting.DateFormatString = "yyyy-MM-dd HH:mm:ss";
                setting.NullValueHandling = NullValueHandling.Ignore;
                //setting.ContractResolver = new CamelCasePropertyNamesContractResolver();//设置字段首字母小写方法
                return setting;
            });
        }

        /// <summary>
        /// 将一个object对象序列化，返回一个byte[]         
        /// </summary> 
        /// <param name="obj">能序列化的对象</param>
        /// <returns></returns> 
        public static byte[] ToBytes(this object obj) {
            using(MemoryStream ms = new MemoryStream()) {
                IFormatter formatter = new BinaryFormatter();
                formatter.Serialize(ms,obj);
                return ms.GetBuffer();
            }
        }

        /// <summary>
        /// 判断是否为Null或者空
        /// </summary>
        /// <param name="obj">对象</param>
        /// <returns></returns>
        public static bool IsNullOrEmpty(this object obj) {
            if(obj == null) {
                return true;
            } else {
                string objStr = obj.ToString();
                return string.IsNullOrWhiteSpace(objStr);
            }
        }

        /// <summary>
        /// 将对象序列化成Json字符串
        /// </summary>
        /// <param name="obj">需要序列化的对象</param>
        /// <returns></returns>
        public static string ToJson(this object obj) {
            return JsonConvert.SerializeObject(obj);
        }

        /// <summary>
        /// 实体类转json数据，速度快
        /// </summary>
        /// <param name="t">实体类</param>
        /// <returns></returns>
        public static string EntityToJson(this object t) {
            if(t == null)
                return null;
            string jsonStr = "";
            jsonStr += "{";
            PropertyInfo[] infos = t.GetType().GetProperties();
            for(int i = 0;i < infos.Length;i++) {
                jsonStr = jsonStr + "\"" + infos[i].Name + "\":\"" + infos[i].GetValue(t).ToString() + "\"";
                if(i != infos.Length - 1)
                    jsonStr += ",";
            }
            jsonStr += "}";
            return jsonStr;
        }

        /// <summary>
        /// 将对象序列化为XML字符串
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="obj">对象</param>
        /// <returns></returns>
        public static string ToXmlStr<T>(this T obj) {
            var jsonStr = obj.ToJson();
            var xmlDoc = JsonConvert.DeserializeXmlNode(jsonStr);
            string xmlDocStr = xmlDoc.InnerXml;

            return xmlDocStr;
        }

        /// <summary>
        /// 将对象序列化为XML字符串
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="obj">对象</param>
        /// <param name="rootNodeName">根节点名(建议设为xml)</param>
        /// <returns></returns>
        public static string ToXmlStr<T>(this T obj,string rootNodeName) {
            var jsonStr = obj.ToJson();
            var xmlDoc = JsonConvert.DeserializeXmlNode(jsonStr,rootNodeName);
            string xmlDocStr = xmlDoc.InnerXml;

            return xmlDocStr;
        }

        /// <summary>
        /// 获取某属性值
        /// </summary>
        /// <param name="obj">对象</param>
        /// <param name="propertyName">属性名</param>
        /// <returns></returns>
        public static object GetPropertyValue(this object obj,string propertyName) {
            return obj.GetType().GetProperty(propertyName,BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static).GetValue(obj);
        }

        /// <summary>
        /// 获取某属性值
        /// </summary>
        /// <param name="obj">对象</param>
        /// <param name="propertyName">属性名</param>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static void SetPropertyValue(this object obj,string propertyName,object value) {
            obj.GetType().GetProperty(propertyName,BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static).SetValue(obj,value);
        }
        /// <summary>
        ///     把对象类型转化为指定类型，转化失败时返回指定的默认值
        /// </summary>
        /// <typeparam name="T"> 动态类型 </typeparam>
        /// <param name="value"> 要转化的源对象 </param>
        /// <param name="defaultValue"> 转化失败返回的指定默认值 </param>
        /// <returns> 转化后的指定类型对象，转化失败时返回指定的默认值 </returns>
        public static T CastTo<T>(this object value,T defaultValue) {
            object result;
            Type type = typeof(T);
            try {
                result = type.IsEnum ? Enum.Parse(type,value.ToString()) : Convert.ChangeType(value,type);
            } catch {
                result = defaultValue;
            }
            return (T)result;
        }
        public static T As<T>(this object obj)
          where T : class {
            return (T)obj;
        }
        public static bool IsIn<T>(this T item,params T[] list) {
            return list.Contains(item);
        }
        /// <summary>
        /// 获取描述
        /// </summary>
        /// <param name="value">布尔值</param>
        public static string Description(this bool value) {
            return value ? "是" : "否";
        }
        #region ==数据转换扩展==

        /// <summary>
        /// 转换成Byte
        /// </summary>
        /// <param name="s">输入字符串</param>
        /// <returns></returns>
        public static byte ToByte(this object s) {
            if(s == null || s == DBNull.Value)
                return 0;

            byte.TryParse(s.ToString(),out byte result);
            return result;
        }

        /// <summary>
        /// 转换成Char
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static char ToChar(this object s) {
            if(s == null || s == DBNull.Value)
                return default;

            char.TryParse(s.ToString(),out char result);
            return result;
        }

        /// <summary>
        /// 转换成short/Int16
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static short ToShort(this object s) {
            if(s == null || s == DBNull.Value)
                return 0;

            short.TryParse(s.ToString(),out short result);
            return result;
        }

        /// <summary>
        /// 转换成Int/Int32
        /// </summary>
        /// <param name="s"></param>
        /// <param name="round">是否四舍五入，默认false</param>
        /// <returns></returns>
        public static int ToInt(this object s,bool round = false) {
            if(s == null || s == DBNull.Value)
                return 0;

            if(s.GetType().IsEnum) {
                return (int)s;
            }

            if(s is bool b)
                return b ? 1 : 0;

            if(int.TryParse(s.ToString(),out int result))
                return result;

            var f = s.ToFloat();
            return round ? Convert.ToInt32(f) : (int)f;
        }

        /// <summary>
        /// 转换成Long/Int64
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static long ToLong(this object s) {
            if(s == null || s == DBNull.Value)
                return 0L;

            long.TryParse(s.ToString(),out long result);
            return result;
        }

        /// <summary>
        /// 转换成Float/Single
        /// </summary>
        /// <param name="s"></param>
        /// <param name="decimals">小数位数</param>
        /// <returns></returns>
        public static float ToFloat(this object s,int? decimals = null) {
            if(s == null || s == DBNull.Value)
                return 0f;

            float.TryParse(s.ToString(),out float result);

            if(decimals == null)
                return result;

            return (float)Math.Round(result,decimals.Value);
        }

        /// <summary>
        /// 转换成Double/Single
        /// </summary>
        /// <param name="s"></param>
        /// <param name="digits">小数位数</param>
        /// <returns></returns>
        public static double ToDouble(this object s,int? digits = null) {
            if(s == null || s == DBNull.Value)
                return 0d;

            double.TryParse(s.ToString(),out double result);

            if(digits == null)
                return result;

            return Math.Round(result,digits.Value);
        }

        /// <summary>
        /// 转换成Decimal
        /// </summary>
        /// <param name="s"></param>
        /// <param name="decimals">小数位数</param>
        /// <returns></returns>
        public static decimal ToDecimal(this object s,int? decimals = null) {
            if(s == null || s == DBNull.Value) return 0m;

            decimal.TryParse(s.ToString(),out decimal result);

            if(decimals == null)
                return result;

            return Math.Round(result,decimals.Value);
        }

        /// <summary>
        /// 转换成DateTime
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static DateTime ToDateTime(this object s) {
            if(s == null || s == DBNull.Value)
                return DateTime.MinValue;

            DateTime.TryParse(s.ToString(),out DateTime result);
            return result;
        }

        /// <summary>
        /// 转换成Date
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static DateTime ToDate(this object s) {
            return s.ToDateTime().Date;
        }

        /// <summary>
        /// 转换成Boolean
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static bool ToBool(this object s) {
            if(s == null) return false;
            s = s.ToString().ToLower();
            if(s.Equals(1) || s.Equals("1") || s.Equals("true") || s.Equals("是") || s.Equals("yes"))
                return true;
            if(s.Equals(0) || s.Equals("0") || s.Equals("false") || s.Equals("否") || s.Equals("no"))
                return false;

            Boolean.TryParse(s.ToString(),out bool result);
            return result;
        }

        /// <summary>
        /// 字符串转Guid
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static Guid ToGuid(this string s) {
            if(s.NotNull() && Guid.TryParse(s,out Guid val))
                return val;

            return Guid.Empty;
        }

        /// <summary>
        /// 字符串转Guid
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static Guid ToGuid(this object s) {
            if(s != null && Guid.TryParse(s.ToString(),out Guid val))
                return val;

            return Guid.Empty;
        }

        /// <summary>
        /// 泛型转换，转换失败会抛出异常
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="s"></param>
        /// <returns></returns>
        public static T To<T>(this object s) {
            return (T)Convert.ChangeType(s,typeof(T));
        }

        #endregion
        #region AutoMapperExt
        /// <summary>
        ///  类型映射
        /// </summary>
        public static T MapTo<T>(this object obj) {
            if(obj == null) return default(T);

            var config = new MapperConfiguration(cfg => cfg.CreateMap(obj.GetType(),typeof(T)));
            var mapper = config.CreateMapper();
            return mapper.Map<T>(obj);
        }

        /// <summary>
        /// 集合列表类型映射
        /// </summary>
        public static List<TDestination> MapToList<TDestination>(this IEnumerable source) {
            Type sourceType = source.GetType().GetGenericArguments()[0];  //获取枚举的成员类型
            var config = new MapperConfiguration(cfg => cfg.CreateMap(sourceType,typeof(TDestination)));
            var mapper = config.CreateMapper();

            return mapper.Map<List<TDestination>>(source);
        }

        /// <summary>
        /// 集合列表类型映射
        /// </summary>
        public static List<TDestination> MapToList<TSource, TDestination>(this IEnumerable<TSource> source) {
            var config = new MapperConfiguration(cfg => cfg.CreateMap(typeof(TSource),typeof(TDestination)));
            var mapper = config.CreateMapper();

            return mapper.Map<List<TDestination>>(source);
        }

        /// <summary>
        /// 类型映射
        /// </summary>
        public static TDestination MapTo<TSource, TDestination>(this TSource source,TDestination destination)
            where TSource : class
            where TDestination : class {
            if(source == null) return destination;

            var config = new MapperConfiguration(cfg => cfg.CreateMap(typeof(TSource),typeof(TDestination)));
            var mapper = config.CreateMapper();
            return mapper.Map<TDestination>(source);
        }
        #endregion
    }
}
